#include <iostream>
#include <string>
using namespace std;

#include <windows.h>
#include "net.hpp"
#include "servicecontrol.hpp"
#include "settings.hpp"

using namespace std;

bool installService(const string &computer,const string &servicename,const string &executable){
    const char *target = computer.c_str();
    if (strcmp(target,".")==0) target = NULL;
    SC_HANDLE sc = OpenSCManager(target,NULL,SC_MANAGER_ALL_ACCESS);

    if (sc == NULL){
        return false;
    }

    SC_HANDLE sv = CreateService(sc, servicename.c_str(), servicename.c_str(),
        GENERIC_READ, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
        executable.c_str(), NULL, NULL, NULL, NULL, NULL);

    if (sv == NULL){
        int err = GetLastError();
        if (err == 1073){ // Already Installed
            //TODO: stop the service and change the executable-path
        } else {
            CloseServiceHandle(sc);
            return false;
        }
    }

    CloseServiceHandle(sv);
    CloseServiceHandle(sc);

    return true;
}

bool installService(const string &computer,const string &username,const string &password,const string &servicename,const string &executable){
    string ipcpath("\\\\");
    ipcpath.append(computer);
    ipcpath.append("\\ipc$");
    share ipcshare(ipcpath,username,password);
    ipcshare.connect();                     // Connect to \\computer\ipc$

    bool success = installService(computer,servicename,executable);

    return success;
}

bool isServiceInstalled(const string &computer,const string &servicename){
    const char *target = computer.c_str();
    if (strcmp(target,".")==0) target = NULL;
    SC_HANDLE sc = OpenSCManager(target, NULL, GENERIC_READ);
    if (sc == NULL){
        return false;
    }

    SC_HANDLE sv = OpenService(sc,servicename.c_str(),SERVICE_QUERY_STATUS);
    CloseServiceHandle(sc);

    return (sv != NULL);
}

bool isServiceInstalled(const string &computer,const string &username,const string &password,const string &servicename){
    string ipcpath("\\\\");
    ipcpath.append(computer);
    ipcpath.append("\\ipc$");
    share ipcshare(ipcpath,username,password);
    ipcshare.connect();                     // Connect to \\computer\ipc$

    return isServiceInstalled(computer,servicename);
}

bool uninstallService(const string &computer,const string &servicename){
    const char *target = computer.c_str();
    if (strcmp(target,".")==0) target = NULL;
    SC_HANDLE sc = OpenSCManager(target, NULL, GENERIC_READ);
    if (sc == NULL){
        return false;
    }

    SC_HANDLE sv = OpenService(sc,servicename.c_str(),DELETE);
    if (sv == NULL){
        CloseServiceHandle(sc);
        return false;
    }

    bool deleted = DeleteService(sv);
    if (!deleted){
        int err = GetLastError();
        CloseServiceHandle(sv);
        CloseServiceHandle(sc);
        if (err == ERROR_SERVICE_MARKED_FOR_DELETE){ // Already marked for deletion
            return true;
        }
        return false;
    }

    CloseServiceHandle(sv);
    CloseServiceHandle(sc);

    return true;
}

bool uninstallService(const string &computer,const string &username,const string &password,const string &servicename){
    string ipcpath("\\\\");
    ipcpath.append(computer);
    ipcpath.append("\\ipc$");

    share ipcshare(ipcpath,username,password);
    ipcshare.connect();                   // Connect to \\computer\ipc$


    bool success = uninstallService(computer,servicename);

    return success;
}

bool startService(const string &computer,const string &servicename,int timeout){
    const char *target = computer.c_str();
    if (strcmp(target,".")==0) target = NULL;
    SC_HANDLE sc = OpenSCManager(target, NULL, GENERIC_READ);
    if (sc == NULL){
        return false;
    }

    SC_HANDLE sv = OpenService(sc,servicename.c_str(),GENERIC_EXECUTE | SERVICE_QUERY_STATUS);
    if (sv == NULL){
        CloseServiceHandle(sc);
        return false;
    }

    bool started = StartService(sv,0,NULL);
    if (!started){
        int err = GetLastError();
        CloseServiceHandle(sv);
        CloseServiceHandle(sc);
        if (err == 1056){ // Already Running
            return true;
        }
        return false;
    }

    SERVICE_STATUS sv_status;

    if (!QueryServiceStatus(sv,&sv_status)){
        return false;
    }

    int time_waited = 0;
    while(sv_status.dwCurrentState != SERVICE_RUNNING && time_waited < timeout){
        Sleep(1000);
        if (!QueryServiceStatus(sv,&sv_status)){
            return false;
        }
        time_waited++;
    }

	return (sv_status.dwCurrentState == SERVICE_RUNNING);
}

bool startService(const string &computer,const string &username,const string &password,const string &servicename,int timeout){
    string ipcpath("\\\\");
    ipcpath.append(computer);
    ipcpath.append("\\ipc$");

    share ipcshare(ipcpath,username,password);
    ipcshare.connect();                   // Connect to \\computer\ipc$

    return startService(computer,servicename,timeout);
}

bool stopService(const string &computer,const string &servicename,int timeout){
    const char *target = computer.c_str();
    if (strcmp(target,".")==0) target = NULL;
    SC_HANDLE sc = OpenSCManager(target, NULL, GENERIC_READ);
    if (sc == NULL){
        return false;
    }

    SC_HANDLE sv = OpenService(sc,servicename.c_str(),GENERIC_EXECUTE | SERVICE_QUERY_STATUS);
    if (sv == NULL){
        CloseServiceHandle(sc);
        return false;
    }

    SERVICE_STATUS sv_status;

    ControlService(sv,SERVICE_CONTROL_STOP,&sv_status);

    int time_waited = 0;
    while(sv_status.dwCurrentState != SERVICE_STOPPED && time_waited < timeout){
        Sleep(1000);
        if (!QueryServiceStatus(sv,&sv_status)){
            return false;
        }
        time_waited++;
    }

	return (sv_status.dwCurrentState == SERVICE_STOPPED);
}

bool stopService(const string &computer,const string &username,const string &password,const string &servicename,int timeout){
    string ipcpath("\\\\");
    ipcpath.append(computer);
    ipcpath.append("\\ipc$");

    share ipcshare(ipcpath,username,password);
    ipcshare.connect();                   // Connect to \\computer\ipc$

    return stopService(computer,servicename,timeout);
}


































